<?php

namespace Lilei\AlipayTransfer;

require_once './vendor/zjalen/alipay-sdk-php-all/aop/AopClient.php';
require_once './vendor/zjalen/alipay-sdk-php-all/aop/AopCertClient.php';
require_once './vendor/zjalen/alipay-sdk-php-all/aop/AlipayConfig.php';
require_once './vendor/zjalen/alipay-sdk-php-all/aop/request/AlipayFundTransUniTransferRequest.php';
require_once './vendor/zjalen/alipay-sdk-php-all/aop/request/AlipayFundTransCommonQueryRequest.php';
require_once './vendor/zjalen/alipay-sdk-php-all/aop/request/AlipayFundAccountQueryRequest.php';
require_once './vendor/zjalen/alipay-sdk-php-all/aop/request/AlipayDataBillEreceiptApplyRequest.php';
require_once './vendor/zjalen/alipay-sdk-php-all/aop/request/AlipayDataBillEreceiptQueryRequest.php';
require_once './vendor/zjalen/alipay-sdk-php-all/aop/request/AlipayDataDataserviceBillDownloadurlQueryRequest.php';

use AopClient;
use AopCertClient;
use AlipayConfig;
use AlipayFundTransUniTransferRequest;
use AlipayFundTransCommonQueryRequest;
use AlipayFundAccountQueryRequest;
use AlipayDataBillEreceiptApplyRequest;
use AlipayDataBillEreceiptQueryRequest;
use AlipayDataDataserviceBillDownloadurlQueryRequest;
use LiLei\Logs\MyMonoLog;

/**
 * @property MyMonoLog $MyMonoLog
 */
class AliPayTransferService
{
    // 开发环境, dev-沙箱，produce-正式
    public string $env = "produce";
    protected array $serverUrl = [
        'dev'       => 'https://openapi-sandbox.dl.alipaydev.com/gateway.do',
        'produce'   => 'https://openapi.alipay.com/gateway.do'
    ];
    // 应用私钥
    public string $app_private_key;
    // APPID 即创建应用后生成
    public string $app_id;
    // 加密密钥
    public string $encrypt_key;
    // 应用私钥
    public string $app_cert;
    // 应用公钥证书文件路径，例如：/foo/appCertPublicKey_2019051064521003.crt
    public string $app_cert_path;
    // 支付宝公钥证书文件路径，例如：/foo/alipayCertPublicKey_RSA2.crt
    public string $alipay_cert_path;
    // 支付宝根证书文件路径，例如：/foo/alipayRootCert.crt
    public string $alipay_root_cert_path;
    // 设置业务产品码
    public string $product_code = 'TRANS_ACCOUNT_NO_PWD';
    // 设置转账业务请求的扩展参数
    public string $business_params = '{"payer_show_name_use_alias":"true"}';
    // 设置描述特定的业务场景
    public string $biz_scene = 'DIRECT_TRANSFER';
    public MyMonoLog $myMonoLog;
    // 日志文件名称
    public string $channel = 'AliPayTransferService';
    // 业务请求参数
    private array $biz_content = [];

    public function __construct(array $config)
    {
        $this->env         = $config['env'] ?? $this->env;
        $this->app_id      = $config['app_id'];
        $dirname           = $config['dirname'] ?? "";
        // 证书模式,https://opendocs.alipay.com/common/055cla?pathHash=41f71ca0
        $this->app_private_key          = $config['app_private_key'];      // 应用私钥
        $this->app_cert_path            = $config['app_cert_path'];        // 应用公钥证书
        $this->alipay_cert_path         = $config['alipay_cert_path'];     // 支付宝公钥证书
        $this->alipay_root_cert_path    = $config['alipay_root_cert_path'];// 支付宝根证书
        $this->encrypt_key = $config['encrypt_key'] ?? "";
        $this->MyMonoLog   = new MyMonoLog();
        if (strlen($dirname) > 0) $this->MyMonoLog->setDirname($dirname);
    }

    /**
     * 回调格式
     *
     * @param int    $code
     * @param string $message
     * @param        $data
     * @return array
     */
    public function callback(int $code, string $message, $data = null): array
    {
        return [
            'code'      => $code,
            'message'   => $message,
            'data'      => $data
        ];
    }// callback() end

    public function getConfig(): AlipayConfig
    {
        $config = new AlipayConfig();
        $config->setServerUrl($this->serverUrl[$this->env]);
        $config->setAppId($this->app_id);
        $config->setCharset('UTF-8');
        $config->setSignType('RSA2');
        $config->setFormat('json');
        $config->setPrivateKey($this->app_private_key);
        $config->setAppCertContent(file_get_contents($this->app_cert_path));
        $config->setAlipayPublicCertContent(file_get_contents($this->alipay_cert_path));
        $config->setRootCertContent(file_get_contents($this->alipay_root_cert_path));
        $config->setEncryptKey($this->encrypt_key);
        return $config;
    }// getConfig() end

    /**
     * 设置业务请求参数
     * @param array $biz_content
     */
    public function setBizContent(array $biz_content): void
    {
        $this->biz_content = $biz_content;
    }// setBizContent() end

    /**
     * 获取业务请求参数
     * @return string
     */
    public function getBizContent(): string
    {
        return json_encode($this->biz_content, JSON_UNESCAPED_UNICODE);
    }// getBizContent() end

    /**
     * https://opendocs.alipay.com/open/62987723_alipay.fund.trans.uni.transfer
     * 单笔转账（转账到支付宝账户）
     * @return array
     */
    public function uniTransfer(): array
    {
        $client  = new AopCertClient($this->getConfig());
        $request = new AlipayFundTransUniTransferRequest();
        $client->isCheckAlipayPublicCert = true;
        $request->setBizContent($this->getBizContent());
        try{
            $responseResult = $client->execute($request);
        }catch(\Exception $e){
            $this->MyMonoLog->channel($this->channel)->error(__CLASS__.'->'.__FUNCTION__.':'.__LINE__);
            $this->MyMonoLog->channel($this->channel)->error($e->getMessage());
            return $this->callback(0, '接口调用报错');
        }
        $responseApiName = str_replace(".","_",$request->getApiMethodName())."_response";
        $response = $responseResult->$responseApiName;
        if (!empty($response->code) && $response->code == 10000)
        {
            $this->MyMonoLog->channel($this->channel)->info(__CLASS__.'->'.__FUNCTION__.':'.__LINE__);
            $this->MyMonoLog->channel($this->channel)->info(json_encode($response, JSON_UNESCAPED_UNICODE));
            $data = json_decode(json_encode($response), true);
            return $this->callback(1, '成功', $data);
        } else {
            $data = [
                'msg'       => $response->msg,
                'sub_code'  => $response->sub_code,
                'sub_msg'   => $response->sub_msg
            ];
            $this->MyMonoLog->channel($this->channel)->error(__CLASS__.'->'.__FUNCTION__.':'.__LINE__);
            $this->MyMonoLog->channel($this->channel)->error($response, JSON_UNESCAPED_UNICODE);
            return $this->callback(0, $response->sub_msg, $data);
        }
    }// uniTransfer() end

    /**
     * https://opendocs.alipay.com/open/58a29899_alipay.fund.trans.common.query
     * 转账业务单据查询接口
     * @return array
     */
    public function commonQuery(): array
    {
        $client  = new AopCertClient($this->getConfig());
        $client->isCheckAlipayPublicCert = true;
        $request = new AlipayFundTransCommonQueryRequest();
        $request->setBizContent($this->getBizContent());
        try{
            $responseResult  = $client->execute($request);
        }catch(\Exception $e){
            $this->MyMonoLog->channel($this->channel)->error(__CLASS__.'->'.__FUNCTION__.':'.__LINE__);
            $this->MyMonoLog->channel($this->channel)->error($this->getBizContent().';error:'.$e->getMessage());
            return $this->callback(0, '接口请求失败');
        }
        $responseApiName = str_replace(".","_",$request->getApiMethodName())."_response";
        $response = $responseResult->$responseApiName;
        if (!empty($response->code) && $response->code == 10000)
        {
            $this->MyMonoLog->channel($this->channel)->info(__CLASS__.'->'.__FUNCTION__.':'.__LINE__);
            $this->MyMonoLog->channel($this->channel)->info(json_encode($response, JSON_UNESCAPED_UNICODE));
            $data = json_decode(json_encode($response, JSON_UNESCAPED_UNICODE), true);
            return $this->callback(1, '成功', $data);
        } else {
            $data = [
                'msg'       => $response->msg,
                'sub_code'  => $response->sub_code,
                'sub_msg'   => $response->sub_msg
            ];
            $this->MyMonoLog->channel($this->channel)->error(__CLASS__.'->'.__FUNCTION__.':'.__LINE__);
            $this->MyMonoLog->channel($this->channel)->error(json_encode($response, JSON_UNESCAPED_UNICODE));
            return $this->callback(0, $response->sub_msg, $data);
        }
    }// commonQuery() end

    /**
     * 支付宝资金账户资产查询
     * https://opendocs.alipay.com/open/1b8a680c_alipay.fund.account.query
     * @return array
     */
    public function accountQuery(): array
    {
        $client  = new AopCertClient($this->getConfig());
        $client->isCheckAlipayPublicCert = true;
        $request = new AlipayFundAccountQueryRequest();
        $request->setBizContent($this->getBizContent());
        try{
            $responseResult = $client->execute($request);
        }catch(\Exception $e){
            $this->MyMonoLog->channel($this->channel)->error(__CLASS__.'->'.__FUNCTION__.':'.__LINE__);
            $this->MyMonoLog->channel($this->channel)->error($e->getMessage());
            return $this->callback(0, '接口请求失败');
        }
        $responseApiName = str_replace(".","_",$request->getApiMethodName())."_response";
        $response = $responseResult->$responseApiName;
        if (!empty($response->code) && $response->code == 10000)
        {
            $data = [
                'available_amount'  => (float)$response->available_amount,// 可用余额
                'freeze_amount'     => (float)$response->freeze_amount,// 冻结余额
            ];
            $this->MyMonoLog->channel($this->channel)->info(__CLASS__.'->'.__FUNCTION__.':'.__LINE__);
            $this->MyMonoLog->channel($this->channel)->info(json_encode($response, JSON_UNESCAPED_UNICODE));
            return $this->callback(1, '成功', $data);
        } else {
            $data = [
                'msg'       => $response->msg,
                'sub_code'  => $response->sub_code,
                'sub_msg'   => $response->sub_msg
            ];
            $this->MyMonoLog->channel($this->channel)->error(__CLASS__.'->'.__FUNCTION__.':'.__LINE__);
            $this->MyMonoLog->channel($this->channel)->error(json_encode($response, JSON_UNESCAPED_UNICODE));
            return $this->callback(0, $response->sub_msg, $data);
        }
    }// accountQuery() end

    /**
     * 申请电子回单(incubating)
     * https://opendocs.alipay.com/open/1aad1956_alipay.data.bill.ereceipt.apply
     * @return array
     */
    public function billEreceiptApply(): array
    {
        $client  = new AopClient($this->getConfig());
        $request = new AlipayDataBillEreceiptApplyRequest();
        $request->setBizContent($this->getBizContent());
        try{
            $responseResult = $client->execute($request);
        }catch(\Exception $e){
            $this->MyMonoLog->channel($this->channel)->error(__CLASS__.'->'.__FUNCTION__.':'.__LINE__);
            $this->MyMonoLog->channel($this->channel)->error($e->getMessage());
            return $this->callback(0, '接口请求失败');
        }
        $responseApiName = str_replace(".","_",$request->getApiMethodName())."_response";
        $response = $responseResult->$responseApiName;
        if (!empty($response->code) && $response->code == 10000)
        {
            $this->MyMonoLog->channel($this->channel)->info(__CLASS__.'->'.__FUNCTION__.':'.__LINE__);
            $this->MyMonoLog->channel($this->channel)->info(json_encode($response, JSON_UNESCAPED_UNICODE));
            $data = json_decode(json_encode($response, JSON_UNESCAPED_UNICODE), true);
            return $this->callback(1, '成功', $data);
        } else {
            $data = [
                'msg'       => $response->msg,
                'sub_code'  => $response->sub_code,
                'sub_msg'   => $response->sub_msg
            ];
            $this->MyMonoLog->channel($this->channel)->error(__CLASS__.'->'.__FUNCTION__.':'.__LINE__);
            $this->MyMonoLog->channel($this->channel)->error(json_encode($response, JSON_UNESCAPED_UNICODE));
            return $this->callback(0, $response->sub_msg, $data);
        }
    }// billEreceiptApply() end

    /**
     * 查询电子回单状态(incubating)
     * https://opendocs.alipay.com/open/30b94a2f_alipay.data.bill.ereceipt.query
     * @return array
     */
    public function billEreceiptQuery(): array
    {
        $client  = new AopClient($this->getConfig());
        $request = new AlipayDataBillEreceiptQueryRequest();
        $request->setBizContent($this->getBizContent());
        try{
            $responseResult = $client->execute($request);
        }catch(\Exception $e){
            $this->MyMonoLog->channel($this->channel)->error(__CLASS__.'->'.__FUNCTION__.':'.__LINE__);
            $this->MyMonoLog->channel($this->channel)->error($e->getMessage());
            return $this->callback(0, '接口请求失败');
        }
        $responseApiName = str_replace(".","_",$request->getApiMethodName())."_response";
        $response = $responseResult->$responseApiName;
        if (!empty($response->code) && $response->code == 10000)
        {
            $this->MyMonoLog->channel($this->channel)->info(__CLASS__.'->'.__FUNCTION__.':'.__LINE__);
            $this->MyMonoLog->channel($this->channel)->info(json_encode($response, JSON_UNESCAPED_UNICODE));
            $data = json_decode(json_encode($response, JSON_UNESCAPED_UNICODE), true);
            return $this->callback(1, '成功', $data);
        } else {
            $this->MyMonoLog->channel($this->channel)->error(__CLASS__.'->'.__FUNCTION__.':'.__LINE__);
            $this->MyMonoLog->channel($this->channel)->error(json_encode($response, JSON_UNESCAPED_UNICODE));
            $data = [
                'msg'       => $response->msg,
                'sub_code'  => $response->sub_code,
                'sub_msg'   => $response->sub_msg
            ];
            return $this->callback(0, $response->sub_msg, $data);
        }
    }// billEreceiptQuery() end

    /**
     * 查询对账单下载地址
     * https://opendocs.alipay.com/open/76606b11_alipay.data.dataservice.bill.downloadurl.query
     * @return array
     */
    public function billDownloadUrlQuery(): array
    {
        $client  = new AopCertClient($this->getConfig());
        $client->isCheckAlipayPublicCert = true;
        $request = new AlipayDataDataserviceBillDownloadurlQueryRequest();
        $request->setBizContent($this->getBizContent());
        try{
            $responseResult = $client->execute($request);
        }catch(\Exception $e){
            $this->MyMonoLog->channel($this->channel)->error(__CLASS__.'->'.__FUNCTION__.':'.__LINE__);
            $this->MyMonoLog->channel($this->channel)->error($e->getMessage());
            return $this->callback(0, '接口请求失败');
        }
        $responseApiName = str_replace(".","_",$request->getApiMethodName())."_response";
        $response = $responseResult->$responseApiName;
        if (!empty($response->code) && $response->code == 10000)
        {
            $this->MyMonoLog->channel($this->channel)->info(__CLASS__.'->'.__FUNCTION__.':'.__LINE__);
            $this->MyMonoLog->channel($this->channel)->info(json_encode($response, JSON_UNESCAPED_UNICODE));
            $data = json_decode(json_encode($response, JSON_UNESCAPED_UNICODE), true);
            return $this->callback(1, '成功', $data);
        } else {
            $data = [
                'msg'       => $response->msg,
                'sub_code'  => $response->sub_code,
                'sub_msg'   => $response->sub_msg
            ];
            $this->MyMonoLog->channel($this->channel)->error(__CLASS__.'->'.__FUNCTION__.':'.__LINE__);
            $this->MyMonoLog->channel($this->channel)->error($data);
            return $this->callback(0, $response->sub_msg, $data);
        }
    }// billDownloadUrlQuery() end
}